package util;
import java.nio.ByteBuffer;
import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SampleIDs {
/**
* Get the SampleSetID from a request.
* The browser uses this to prevent double counting of fingerprints.
*
* @param request
* @param context
* @return
* @throws ServletException
*/
public static String getSampleSetID(HttpServletRequest request, ServletContext context) throws ServletException {
Cookie cookies[] = request.getCookies();
if (cookies == null) {
// No SampleIDs. Just return an empty list.
return null;
}
// Find the SampleIDs cookie.
String sampleSetID = null;
for (int i = 0; i < cookies.length; ++i) {
if (cookies[i].getName().equals("SampleSetID")) {
sampleSetID = cookies[i].getValue();
break;
}
}
return sampleSetID;
}
/**
* Save the encrypted SampleSetID in a cookie in the HTTP response.
*
* @param response
* @param sampleIDs
* @param context
*/
public static void saveSampleSetID(HttpServletResponse response, String sampleSetID, ServletContext context) {
if (sampleSetID == null) {
// This should never happen, but if it somehow did it could cause a null pointer exception.
return;
} else {
Cookie sampleSetIdCookie = new Cookie("SampleSetID", sampleSetID);
sampleSetIdCookie.setMaxAge(60 * 60 * 24 * 30);// 30 days
response.addCookie(sampleSetIdCookie);
}
}
/**
* Decrypt an integer from a String.
*
* @param encrypted
* @param context
* @return
* @throws ServletException
*/
private static Integer decryptInteger(String encrypted, ServletContext context) throws ServletException {
String encryptedParts[] = encrypted.split("\\|");
if (encryptedParts.length != 3) {
throw new ServletException("Invalid encrypted string.");
}
/* Get password. */
String password = context.getInitParameter("SampleSetIDEncryptionPassword");
/* Extract the encrypted data, initialisation vector, and salt from the cookie. */
Decoder decoder = Base64.getDecoder();
byte ciphertext[] = decoder.decode(encryptedParts[0]);
byte iv[] = decoder.decode(encryptedParts[1]);
byte salt[] = decoder.decode(encryptedParts[2]);
byte plainbytes[];
try {
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
plainbytes = cipher.doFinal(ciphertext);
} catch (Exception ex) {
throw new ServletException(ex);
}
return ByteBuffer.wrap(plainbytes).asIntBuffer().get();
}
/**
* Encrypt an integer to a String.
*
* @param integer
* @param context
* @return
* @throws ServletException
*/
private static String encryptInteger(Integer integer, ServletContext context) throws ServletException {
/* Get password. */
String password = context.getInitParameter("SampleSetIDEncryptionPassword");
/* Generate salt. */
SecureRandom rand = new SecureRandom();
byte salt[] = new byte[8];
rand.nextBytes(salt);
byte[] iv;
byte[] ciphertext;
try {
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the SampleSetID. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
iv = params.getParameterSpec(IvParameterSpec.class).getIV();
ciphertext = cipher.doFinal(ByteBuffer.allocate(4).putInt(integer).array());
} catch (Exception ex) {
throw new ServletException(ex);
}
/* Store the encrypted SampleSetID in a cookie */
Encoder encoder = Base64.getEncoder();
String encryptedStr = encoder.encodeToString(ciphertext) + "|" + encoder.encodeToString(iv) + "|" + encoder.encodeToString(salt);
return encryptedStr;
}
}